package com.lagou.dubbo.filter;

import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

@Activate(group = {CommonConstants.CONSUMER})
public class TPMonitorFilter implements Filter {


    private static ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5) ;


    private  static Map<String,List<MethodMonitor>> methodMap = new ConcurrentHashMap<>();


    class MethodMonitor {


        private long date;

        private long time;


        public long getDate() {
            return date;
        }

        public void setDate(long date) {
            this.date = date;
        }

        public long getTime() {
            return time;
        }

        public void setTime(long time) {
            this.time = time;
        }
    }




    static {

        executorService.scheduleAtFixedRate(()->{
            try {
                for (String  methodName: methodMap.keySet() ) {
                    System.out.println("方法"+ methodName + "： 的TP90是"+ getTp(methodName, 0.9));
                    System.out.println("方法"+ methodName + "： 的TP99是"+ getTp(methodName, 0.99));
                }
                System.out.println("汇总时间为"+ new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()));
            }catch (Exception e){
                e.printStackTrace();
            }
        },5,5, TimeUnit.SECONDS);

    }


    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        long  startTime  = System.currentTimeMillis();
        try {
            // 执行方法
            return  invoker.invoke(invocation);
        } finally {
            long time =  System.currentTimeMillis() - startTime;
            String methodName = invocation.getMethodName();
            List<MethodMonitor> methodMonitorList =  methodMap.get(methodName);
            if (methodMonitorList == null){
                methodMonitorList = new CopyOnWriteArrayList<>();
                methodMap.put(methodName,methodMonitorList);
            }
            MethodMonitor methodMonitor = new MethodMonitor();
            methodMonitor.setTime(time);
            methodMonitor.setDate(System.currentTimeMillis());
            methodMonitorList.add(methodMonitor);
        }
    }



    private static synchronized long getTp(String name , double rate){

        List<MethodMonitor> methodMonitorList =   methodMap.get(name);
        List<MethodMonitor> matchingInfo  = new ArrayList<>();
        long effectiveTime = System.currentTimeMillis() - 60000;

        for (MethodMonitor methodMonitor : methodMonitorList){
            if (methodMonitor.getDate() > effectiveTime){
                matchingInfo.add(methodMonitor);
            }
        }
        matchingInfo =  matchingInfo.stream().sorted(Comparator.comparing(MethodMonitor::getTime)).collect(Collectors.toList());

        methodMonitorList.clear();
        methodMonitorList.addAll(matchingInfo);

        int index = (int) (matchingInfo.size() * rate);

        return matchingInfo.get(index).getTime();
    }

}
